package com.ssy.lingxi.settle.accounts.serviceimpl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.ssy.lingxi.common.constant.settle.ReceiptInvoiceOrderTypeEnum;
import com.ssy.lingxi.common.constant.settle.SettlementOrderTypeEnum;
import com.ssy.lingxi.common.constant.settle.SettlementTypeEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.message.api.constant.MessageTemplateCode;
import com.ssy.lingxi.message.api.vo.request.SystemMessageRequest;
import com.ssy.lingxi.pay.api.dto.request.eAccount.PlatFormTransferRequest;
import com.ssy.lingxi.pay.api.model.vo.response.allInPay.ApplicationTransferRespVO;
import com.ssy.lingxi.report.api.enums.OperateDataSourceEnum;
import com.ssy.lingxi.report.api.enums.SettleAccountPlatformScoreOperateTypeEnum;
import com.ssy.lingxi.report.api.vo.request.OperateNoticeVO;
import com.ssy.lingxi.settle.accounts.entity.PlatformScoreSettlementDO;
import com.ssy.lingxi.settle.accounts.entity.PlatformScoreSettlementDetailDO;
import com.ssy.lingxi.settle.accounts.model.bo.PayProveBO;
import com.ssy.lingxi.settle.accounts.model.constant.CommonBooleanEnum;
import com.ssy.lingxi.settle.accounts.model.constant.PlatformScoreSettlementExcelEnum;
import com.ssy.lingxi.settle.accounts.model.constant.SettlementStatusEnum;
import com.ssy.lingxi.settle.accounts.model.constant.SettlementWayEnum;
import com.ssy.lingxi.settle.accounts.model.vo.request.*;
import com.ssy.lingxi.settle.accounts.model.vo.response.CommunicationPayProveVO;
import com.ssy.lingxi.settle.accounts.model.vo.response.PagePlatformScoreSettlementDetailVO;
import com.ssy.lingxi.settle.accounts.model.vo.response.PlatformScoreSettlementDetailVO;
import com.ssy.lingxi.settle.accounts.model.vo.response.PlatformScoreSettlementVO;
import com.ssy.lingxi.settle.accounts.repository.PlatformScoreSettlementDetailRepository;
import com.ssy.lingxi.settle.accounts.repository.PlatformScoreSettlementRepository;
import com.ssy.lingxi.settle.accounts.service.IFeignService;
import com.ssy.lingxi.settle.accounts.service.IPlatformScoreSettlementService;
import com.ssy.lingxi.settle.accounts.utils.OrderDateTimeUtil;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.poi.ss.usermodel.CellStyle;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 平台积分结算接口实现
 * @author 伍将
 * @date 2020/10/29
 * @version 2.0.0
 */
@Service
public class PlatformScoreSettlementServiceImpl implements IPlatformScoreSettlementService {

    @Resource
    private PlatformScoreSettlementRepository repository;

    @Resource
    private PlatformScoreSettlementDetailRepository detailRepository;

    @Resource
    private IFeignService feignService;


    /**
     * 分页查询应收账款结算
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser: 
     * @param pageVO: 
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.common.response.PageData < com.ssy.lingxi.settle.accounts.mode.vo.response.PlatformScoreSettlementVO>>
     **/
    @Override
    public Wrapper<PageData<PlatformScoreSettlementVO>> pageReceivableSettlement(UserLoginCacheDTO sysUser, PlatformScoreSettlementPageVO pageVO) {
        return pageSettlement(sysUser, pageVO, false);
    }

    /**
     * 确认对账完成
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser:
     * @param completeVO:
     * @return com.ssy.lingxi.common.response.Wrapper
     **/
    @Override
    public Wrapper<Void> confirmAccountComplete(UserLoginCacheDTO sysUser, ConfirmAccountCompleteVO completeVO) {
        PlatformScoreSettlementDO entity = repository.findById(completeVO.getSettlementId()).orElse(null);
        if (entity == null) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SCORE_SETTLEMENT_NOT_EXIST);
        }
        if (!entity.getStatus().equals(SettlementStatusEnum.TO_BE_ACCOUNT_COMPLETE.getCode())) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SCORE_SETTLEMENT_NO_CONFIRM_ACCOUNT_COMPLETE);
        }
        entity.setStatus(SettlementStatusEnum.TO_BE_PAY.getCode());
        entity.setUpdateTime(System.currentTimeMillis());
        repository.saveAndFlush(entity);

        // 新增操作通知
        List<OperateNoticeVO> noticeVOList = new ArrayList<>();
        // 支付方待对账-1，待付款+1
        OperateNoticeVO noticeVO = new OperateNoticeVO();
        noticeVO.setMemberId(0L);
        noticeVO.setRoleId(0L);
        noticeVO.setDataSource(OperateDataSourceEnum.SETTLE_ACCOUNT_PLATFORM_SCORE.getCode());
        noticeVO.setReduceOperateType(SettleAccountPlatformScoreOperateTypeEnum.TO_BE_ACCOUNTS.getCode());
        noticeVO.setReduceCount(1L);
        noticeVO.setIncreaseOperateType(SettleAccountPlatformScoreOperateTypeEnum.TO_BE_PAY.getCode());
        noticeVO.setIncreaseCount(1L);
        noticeVOList.add(noticeVO);
        // 收款方待对账-1，待付款+1
        noticeVO = new OperateNoticeVO();
        noticeVO.setMemberId(entity.getMemberId());
        noticeVO.setRoleId(entity.getRoleId());
        noticeVO.setDataSource(OperateDataSourceEnum.SETTLE_ACCOUNT_PLATFORM_SCORE.getCode());
        noticeVO.setReduceOperateType(SettleAccountPlatformScoreOperateTypeEnum.TO_BE_ACCOUNTS.getCode());
        noticeVO.setReduceCount(1L);
        noticeVO.setIncreaseOperateType(SettleAccountPlatformScoreOperateTypeEnum.TO_BE_PAY.getCode());
        noticeVO.setIncreaseCount(1L);
        noticeVOList.add(noticeVO);
        feignService.addSystemOperateNoticeList(noticeVOList);

        // 新增系统通知
        List<SystemMessageRequest> requestList = new ArrayList<>();
        List<String> params = new ArrayList<>();
        params.add(entity.getSettlementNo());
        SystemMessageRequest request = new SystemMessageRequest();
        request.setMemberId(0L);
        request.setRoleId(0L);
        request.setMessageNotice(MessageTemplateCode.integral_upload_bill);
        request.setParams(params);
        requestList.add(request);
        request = new SystemMessageRequest();
        request.setMemberId(entity.getMemberId());
        request.setRoleId(entity.getRoleId());
        request.setMessageNotice(MessageTemplateCode.integral_upload_bill);
        request.setParams(params);
        requestList.add(request);
        feignService.batchSendSystemMessage(requestList);

        return Wrapper.success();
    }

    /**
     * 确认付款凭证
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser:
     * @param confirmVO:
     * @return com.ssy.lingxi.common.response.Wrapper
     **/
    @Override
    public Wrapper<Void> confirmPayProve(UserLoginCacheDTO sysUser, ConfirmPayProve confirmVO) {
        PlatformScoreSettlementDO entity = repository.findById(confirmVO.getId()).orElse(null);
        if (entity == null) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SCORE_SETTLEMENT_NOT_EXIST);
        }
        if (!entity.getStatus().equals(SettlementStatusEnum.TO_BE_RECEIPT.getCode())) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SCORE_SETTLEMENT_NO_CONFIRM_PAY_PROVE);
        }
        if (confirmVO.getStatus().equals(CommonBooleanEnum.YES.getCode())) {
            entity.setStatus(SettlementStatusEnum.COMPLETE.getCode());
        } else {
            entity.setStatus(SettlementStatusEnum.TO_BE_PAY.getCode());
        }
        entity.setUpdateTime(System.currentTimeMillis());
        repository.saveAndFlush(entity);

        // 新增操作通知
        List<OperateNoticeVO> noticeVOList = new ArrayList<>();
        // 支付方待收款-1，已完成/待付款+1
        OperateNoticeVO noticeVO = new OperateNoticeVO();
        noticeVO.setMemberId(0L);
        noticeVO.setRoleId(0L);
        noticeVO.setDataSource(OperateDataSourceEnum.SETTLE_ACCOUNT_PLATFORM_SCORE.getCode());
        noticeVO.setReduceOperateType(SettleAccountPlatformScoreOperateTypeEnum.TO_BE_RECEIPT.getCode());
        noticeVO.setReduceCount(1L);
        if (SettlementStatusEnum.COMPLETE.getCode().equals(entity.getStatus())) {
            noticeVO.setIncreaseOperateType(SettleAccountPlatformScoreOperateTypeEnum.COMPLETE.getCode());
        } else if (SettlementStatusEnum.TO_BE_PAY.getCode().equals(entity.getStatus())) {
            noticeVO.setIncreaseOperateType(SettleAccountPlatformScoreOperateTypeEnum.TO_BE_PAY.getCode());
        }
        noticeVO.setIncreaseCount(1L);
        noticeVOList.add(noticeVO);
        // 收款方待收款-1，已完成/待付款+1
        noticeVO = new OperateNoticeVO();
        noticeVO.setMemberId(entity.getMemberId());
        noticeVO.setRoleId(entity.getRoleId());
        noticeVO.setDataSource(OperateDataSourceEnum.SETTLE_ACCOUNT_PLATFORM_SCORE.getCode());
        noticeVO.setReduceOperateType(SettleAccountPlatformScoreOperateTypeEnum.TO_BE_RECEIPT.getCode());
        noticeVO.setReduceCount(1L);
        if (SettlementStatusEnum.COMPLETE.getCode().equals(entity.getStatus())) {
            noticeVO.setIncreaseOperateType(SettleAccountPlatformScoreOperateTypeEnum.COMPLETE.getCode());
        } else if (SettlementStatusEnum.TO_BE_PAY.getCode().equals(entity.getStatus())) {
            noticeVO.setIncreaseOperateType(SettleAccountPlatformScoreOperateTypeEnum.TO_BE_PAY.getCode());
        }
        noticeVO.setIncreaseCount(1L);
        noticeVOList.add(noticeVO);
        feignService.addSystemOperateNoticeList(noticeVOList);

        if (SettlementStatusEnum.TO_BE_PAY.getCode().equals(entity.getStatus())) {
            // 新增系统通知
            List<SystemMessageRequest> requestList = new ArrayList<>();
            List<String> params = new ArrayList<>();
            params.add(entity.getSettlementNo());
            SystemMessageRequest request = new SystemMessageRequest();
            request.setMemberId(0L);
            request.setRoleId(0L);
            request.setMessageNotice(MessageTemplateCode.integral_upload_bill);
            request.setParams(params);
            requestList.add(request);
            request = new SystemMessageRequest();
            request.setMemberId(entity.getMemberId());
            request.setRoleId(entity.getRoleId());
            request.setMessageNotice(MessageTemplateCode.integral_upload_bill);
            request.setParams(params);
            requestList.add(request);
            feignService.batchSendSystemMessage(requestList);
        }

        return Wrapper.success();
    }

    /**
     * 收款方查看凭证
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser:
     * @param id:
     * @return com.ssy.lingxi.common.response.Wrapper<java.util.List < com.ssy.lingxi.settle.accounts.mode.bo.PayProveBO>>
     **/
    @Override
    public Wrapper<List<PayProveBO>> getReceivablePayProve(UserLoginCacheDTO sysUser, Long id) {
        return getPayProve(sysUser, id);
    }

    /**
     * 获取应收款账款结算详情
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser:
     * @param id:
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.settle.accounts.mode.vo.response.PlatformScoreSettlementDetailVO>
     **/
    @Override
    public Wrapper<PlatformScoreSettlementDetailVO> getReceivableDetail(UserLoginCacheDTO sysUser, Long id) {
        return getDetail(sysUser, id);
    }

    /**
     * 分页查询应付账款结算
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser: 
     * @param pageVO: 
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.common.response.PageData < com.ssy.lingxi.settle.accounts.mode.vo.response.PlatformScoreSettlementVO>>
     **/
    @Override
    public Wrapper<PageData<PlatformScoreSettlementVO>> pagePayableSettlement(UserLoginCacheDTO sysUser, PlatformScoreSettlementPageVO pageVO) {
        return pageSettlement(sysUser, pageVO, true);
    }

    /**
     * 支付
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser:
     * @param payVO:
     * @return com.ssy.lingxi.common.response.Wrapper
     **/
    @Override
    public Wrapper<Void> pay(UserLoginCacheDTO sysUser, PayVO payVO) {
        PlatformScoreSettlementDO entity = repository.findById(payVO.getId()).orElse(null);
        if (entity == null) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SCORE_SETTLEMENT_NOT_EXIST);
        }
        if (!entity.getStatus().equals(SettlementStatusEnum.TO_BE_PAY.getCode())) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SCORE_SETTLEMENT_NO_PAY);
        }
        entity.setPayProveList(payVO.getProveList());
        entity.setStatus(SettlementStatusEnum.TO_BE_RECEIPT.getCode());
        entity.setUpdateTime(System.currentTimeMillis());
        entity.setPayTime(System.currentTimeMillis());
        repository.saveAndFlush(entity);

        // 新增操作通知
        List<OperateNoticeVO> noticeVOList = new ArrayList<>();
        // 支付方待付款-1，待收款+1
        OperateNoticeVO noticeVO = new OperateNoticeVO();
        noticeVO.setMemberId(0L);
        noticeVO.setRoleId(0L);
        noticeVO.setDataSource(OperateDataSourceEnum.SETTLE_ACCOUNT_PLATFORM_SCORE.getCode());
        noticeVO.setReduceOperateType(SettleAccountPlatformScoreOperateTypeEnum.TO_BE_PAY.getCode());
        noticeVO.setReduceCount(1L);
        noticeVO.setIncreaseOperateType(SettleAccountPlatformScoreOperateTypeEnum.TO_BE_RECEIPT.getCode());
        noticeVO.setIncreaseCount(1L);
        noticeVOList.add(noticeVO);
        // 收款方待付款-1，待收款+1
        noticeVO = new OperateNoticeVO();
        noticeVO.setMemberId(entity.getMemberId());
        noticeVO.setRoleId(entity.getRoleId());
        noticeVO.setDataSource(OperateDataSourceEnum.SETTLE_ACCOUNT_PLATFORM_SCORE.getCode());
        noticeVO.setReduceOperateType(SettleAccountPlatformScoreOperateTypeEnum.TO_BE_PAY.getCode());
        noticeVO.setReduceCount(1L);
        noticeVO.setIncreaseOperateType(SettleAccountPlatformScoreOperateTypeEnum.TO_BE_RECEIPT.getCode());
        noticeVO.setIncreaseCount(1L);
        noticeVOList.add(noticeVO);
        feignService.addSystemOperateNoticeList(noticeVOList);

        // 新增系统通知
        List<SystemMessageRequest> requestList = new ArrayList<>();
        List<String> params = new ArrayList<>();
        params.add(entity.getSettlementNo());
        SystemMessageRequest request = new SystemMessageRequest();
        request.setMemberId(0L);
        request.setRoleId(0L);
        request.setMessageNotice(MessageTemplateCode.integral_gathering);
        request.setParams(params);
        requestList.add(request);
        request = new SystemMessageRequest();
        request.setMemberId(entity.getMemberId());
        request.setRoleId(entity.getRoleId());
        request.setMessageNotice(MessageTemplateCode.integral_gathering);
        request.setParams(params);
        requestList.add(request);
        feignService.batchSendSystemMessage(requestList);

        return Wrapper.success();
    }

    /**
     * 付款方查看凭证
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser:
     * @param id:
     * @return com.ssy.lingxi.common.response.Wrapper<java.util.List < com.ssy.lingxi.settle.accounts.mode.bo.PayProveBO>>
     **/
    @Override
    public Wrapper<List<PayProveBO>> getPayablePayProve(UserLoginCacheDTO sysUser, Long id) {
        return getPayProve(sysUser, id);
    }

    /**
     * 获取应付账款结算详情
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser:
     * @param id:
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.settle.accounts.mode.vo.response.PlatformScoreSettlementDetailVO>
     **/
    @Override
    public Wrapper<PlatformScoreSettlementDetailVO> getPayableDetail(UserLoginCacheDTO sysUser, Long id) {
        return getDetail(sysUser, id);
    }

    /**
     * 分页查询平台结算
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser:
     * @param pageVO:
     * @param isSettlement:
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.common.response.PageData < com.ssy.lingxi.settle.accounts.mode.vo.response.PlatformScoreSettlementVO>>
     **/
    private Wrapper<PageData<PlatformScoreSettlementVO>> pageSettlement(UserLoginCacheDTO sysUser, PlatformScoreSettlementPageVO pageVO, Boolean isSettlement) {
        // step 1: 组装查询条件
        Specification<PlatformScoreSettlementDO> spec =  (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            if (!pageVO.getStatus().equals(SettlementStatusEnum.ALL.getCode())) {
                list.add(criteriaBuilder.equal(root.get("status").as(Integer.class), pageVO.getStatus()));
            }
            if (StringUtils.hasLength(pageVO.getStartTime())) {
                list.add(criteriaBuilder.greaterThanOrEqualTo(root.get("settlementDate").as(Long.class), DateUtil.parse(pageVO.getStartTime()).getTime()));
            }
            if (StringUtils.hasLength(pageVO.getEndTime())) {
                list.add(criteriaBuilder.lessThanOrEqualTo(root.get("settlementDate").as(Long.class), DateUtil.parse(pageVO.getEndTime()).getTime()));
            }
            if (isSettlement) {
                if (StringUtils.hasLength(pageVO.getSettlementName())) {
                    list.add(criteriaBuilder.like(root.get("settlementName").as(String.class), "%" + pageVO.getSettlementName().trim() + "%"));
                }
            } else {
                list.add(criteriaBuilder.equal(root.get("memberId").as(Long.class), sysUser.getMemberId()));
                list.add(criteriaBuilder.equal(root.get("roleId").as(Long.class), sysUser.getMemberRoleId()));
            }
            if (StringUtils.hasLength(pageVO.getSettlementNo())) {
                list.add(criteriaBuilder.like(root.get("settlementNo").as(String.class), "%" + pageVO.getSettlementNo().trim() + "%"));
            }
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        // step 2: 组装分页参数
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("id").descending());

        // step 3: 分页查询数据
        Page<PlatformScoreSettlementDO> result = repository.findAll(spec, page);

        // step 4: 组装返回数据
        List<PlatformScoreSettlementVO> resultList = result.getContent().stream().map(r -> {
            PlatformScoreSettlementVO queryVO = new PlatformScoreSettlementVO();
            queryVO.setId(r.getId());
            queryVO.setSettlementNo(r.getSettlementNo());
            queryVO.setSettlementDate(DateUtil.format(DateUtil.date(r.getSettlementDate()), "yyyy-MM-dd"));
            queryVO.setEstimatedPaymentDate(DateUtil.format(DateUtil.date(r.getEstimatedPaymentDate()), "yyyy-MM-dd"));
            queryVO.setPayTime(Optional.ofNullable(r.getPayTime()).filter(f -> f.compareTo(0L)>0).map(map -> DateUtil.format(DateUtil.date(map), "yyyy-MM-dd HH:mm:ss")).orElse(""));
            queryVO.setSettlementWayName(SettlementWayEnum.getMessage(r.getSettlementWay()));
            queryVO.setSettlementName(r.getSettlementName());
            queryVO.setTotalCount(r.getTotalCount());
            queryVO.setScore(r.getScore());
            queryVO.setRatio(r.getRatio());
            queryVO.setAmount(BigDecimal.valueOf(r.getAmount()).setScale(2, RoundingMode.HALF_UP).doubleValue());
            queryVO.setSettlementTime(DateUtil.format(DateUtil.date(r.getSettlementTime()), "yyyy-MM-dd HH:mm"));
            queryVO.setStatus(r.getStatus());
            queryVO.setStatusName(SettlementStatusEnum.getMessage(r.getStatus()));
            queryVO.setPayWay(r.getPayWay());
            queryVO.setPayWayName(SettlementTypeEnum.getName(r.getPayWay()));
            queryVO.setMemberId(r.getMemberId());
            queryVO.setRoleId(r.getRoleId());

            return queryVO;
        }).collect(Collectors.toList());

        return Wrapper.success(new PageData<>(result.getTotalElements(), resultList));
    }

    /**
     * 获取支付凭证
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser:
     * @param id:
     * @return com.ssy.lingxi.common.response.Wrapper<java.util.List < com.ssy.lingxi.settle.accounts.mode.bo.PayProveBO>>
     **/
    private Wrapper<List<PayProveBO>> getPayProve(UserLoginCacheDTO sysUser, Long id) {

        PlatformScoreSettlementDO entity = repository.findById(id).orElse(null);
        if (entity == null) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SCORE_SETTLEMENT_NOT_EXIST);
        }

        return Wrapper.success(entity.getPayProveList());
    }

    /**
     * 获取积分结算详情
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser:
     * @param id:
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.settle.accounts.mode.vo.response.PlatformScoreSettlementDetailVO>
     **/
    private Wrapper<PlatformScoreSettlementDetailVO> getDetail(UserLoginCacheDTO sysUser, Long id) {
        PlatformScoreSettlementDO entity = repository.findById(id).orElse(null);
        if (entity == null) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SCORE_SETTLEMENT_NOT_EXIST);
        }

        PlatformScoreSettlementDetailVO result = new PlatformScoreSettlementDetailVO();
        result.setId(entity.getId());
        result.setSettlementNo(entity.getSettlementNo());
        result.setSettlementWayName(SettlementWayEnum.getMessage(entity.getSettlementWay()));
        result.setTotalCount(entity.getTotalCount());
        result.setAmount(BigDecimal.valueOf(entity.getAmount()).setScale(2, RoundingMode.HALF_UP).doubleValue());
        result.setSettlementDate(DateUtil.format(DateUtil.date(entity.getSettlementDate()), "yyyy-MM-dd"));
        result.setEstimatedPaymentDate(DateUtil.format(DateUtil.date(entity.getEstimatedPaymentDate()), "yyyy-MM-dd"));
        result.setStatusName(SettlementStatusEnum.getMessage(entity.getStatus()));

        return Wrapper.success(result);
    }

    /**
     * 分页查询应收款账款结算详情
     * @author 伍将
     * @date 2020/10/30
     * @param sysUser: 
     * @param pageVO: 
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.common.response.PageData < com.ssy.lingxi.settle.accounts.mode.vo.response.PagePlatformScoreSettlementDetailVO>>
     **/
    @Override
    public Wrapper<PageData<PagePlatformScoreSettlementDetailVO>> pageReceivableSettlementDetail(UserLoginCacheDTO sysUser, PlatformScoreSettlementDetailPageVO pageVO) {
        return pageSettlementDetail(sysUser, pageVO, false);
    }

    /**
     * 分页查询应付款账款结算详情
     * @author 伍将
     * @date 2020/10/30
     * @param sysUser: 
     * @param pageVO: 
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.common.response.PageData < com.ssy.lingxi.settle.accounts.mode.vo.response.PagePlatformScoreSettlementDetailVO>>
     **/
    @Override
    public Wrapper<PageData<PagePlatformScoreSettlementDetailVO>> pagePayableSettlementDetail(UserLoginCacheDTO sysUser, PlatformScoreSettlementDetailPageVO pageVO) {
        return pageSettlementDetail(sysUser, pageVO, true);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Wrapper<Void> allInPay(UserLoginCacheDTO sysUser, AllInPayVO payVO) {
        // step1: 查询平台积分结算
        PlatformScoreSettlementDO entity = repository.findById(payVO.getId()).orElse(null);
        // step2: 校验
        if (entity == null) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SCORE_SETTLEMENT_NOT_EXIST);
        }
        if (!entity.getStatus().equals(SettlementStatusEnum.TO_BE_PAY.getCode())) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SCORE_SETTLEMENT_NO_PAY);
        }
        // step3: 更新状态已完成
        entity.setStatus(SettlementStatusEnum.COMPLETE.getCode());
        entity.setUpdateTime(System.currentTimeMillis());
        entity.setPayTime(System.currentTimeMillis());
        // 生成支付流水号
        String tradeNo = entity.getSettlementNo() + "-" + RandomStringUtils.random(7, "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");
        entity.setTradeNo(tradeNo);
        repository.saveAndFlush(entity);
        // step4: 通联支付
        PlatFormTransferRequest allInPayRequest = new PlatFormTransferRequest();
        allInPayRequest.setMemberId(entity.getMemberId()); // 会员id(收款方)
        allInPayRequest.setMemberRoleId(entity.getRoleId()); // 会员角色id(收款方)
        allInPayRequest.setOrderCode(tradeNo); // 商户订单号
        allInPayRequest.setPayMoney(entity.getAmount()); // 金额
        Wrapper<ApplicationTransferRespVO> payWrapper = feignService.platFormTransfer(allInPayRequest);
        if (payWrapper == null) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Wrapper.fail(ResponseCode.SERVICE_PAY_ERROR);
        }
        if (payWrapper.getCode() != ResponseCode.SUCCESS.getCode()) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Wrapper.fail(payWrapper.getCode(), payWrapper.getMessage());
        }
        // step5: 消息推送
        List<OperateNoticeVO> noticeVOList = new ArrayList<>();
        // 支付方待付款-1，待收款+1
        OperateNoticeVO noticeVO = new OperateNoticeVO();
        noticeVO.setMemberId(0L);
        noticeVO.setRoleId(0L);
        noticeVO.setDataSource(OperateDataSourceEnum.SETTLE_ACCOUNT_PLATFORM_SCORE.getCode());
        noticeVO.setReduceOperateType(SettleAccountPlatformScoreOperateTypeEnum.TO_BE_PAY.getCode());
        noticeVO.setReduceCount(1L);
        noticeVO.setIncreaseOperateType(SettleAccountPlatformScoreOperateTypeEnum.TO_BE_RECEIPT.getCode());
        noticeVO.setIncreaseCount(1L);
        noticeVOList.add(noticeVO);
        // 收款方待付款-1，待收款+1
        noticeVO = new OperateNoticeVO();
        noticeVO.setMemberId(entity.getMemberId());
        noticeVO.setRoleId(entity.getRoleId());
        noticeVO.setDataSource(OperateDataSourceEnum.SETTLE_ACCOUNT_PLATFORM_SCORE.getCode());
        noticeVO.setReduceOperateType(SettleAccountPlatformScoreOperateTypeEnum.TO_BE_PAY.getCode());
        noticeVO.setReduceCount(1L);
        noticeVO.setIncreaseOperateType(SettleAccountPlatformScoreOperateTypeEnum.TO_BE_RECEIPT.getCode());
        noticeVO.setIncreaseCount(1L);
        noticeVOList.add(noticeVO);
        feignService.addSystemOperateNoticeList(noticeVOList);

        // 新增系统通知
        List<SystemMessageRequest> requestList = new ArrayList<>();
        List<String> params = new ArrayList<>();
        params.add(entity.getSettlementNo());
        SystemMessageRequest request = new SystemMessageRequest();
        request.setMemberId(0L);
        request.setRoleId(0L);
        request.setMessageNotice(MessageTemplateCode.integral_gathering);
        request.setParams(params);
        requestList.add(request);
        request = new SystemMessageRequest();
        request.setMemberId(entity.getMemberId());
        request.setRoleId(entity.getRoleId());
        request.setMessageNotice(MessageTemplateCode.integral_gathering);
        request.setParams(params);
        requestList.add(request);
        feignService.batchSendSystemMessage(requestList);
        return Wrapper.success();
    }

    @Override
    public Wrapper<CommunicationPayProveVO> getAllInPayablePayProve(UserLoginCacheDTO sysUser, Long id) {
        // step1: 查询平台积分结算
        PlatformScoreSettlementDO entity = repository.findById(id).orElse(null);
        // step2: 校验
        if (entity == null) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SCORE_SETTLEMENT_NOT_EXIST);
        }
        CommunicationPayProveVO data = new CommunicationPayProveVO();
        data.setSettlementName(entity.getSettlementName());
        data.setAmount(entity.getAmount());
        data.setPayWayName(SettlementTypeEnum.getName(entity.getPayWay()));
        data.setSettlementTime(DateUtil.format(new Date(entity.getSettlementDate()), DatePattern.NORM_DATETIME_PATTERN));
        data.setStatus(SettlementStatusEnum.getMessage(entity.getStatus()));
        return Wrapper.success(data);
    }

    @Override
    public void receivableExport(UserLoginCacheDTO sysUser, HttpServletResponse response, PlatformScoreSettlementDetailPageVO queryParameter) {
        exportCommon(sysUser, response, queryParameter, true);
    }

    @Override
    public void payableExport(UserLoginCacheDTO sysUser, HttpServletResponse response, PlatformScoreSettlementDetailPageVO queryParameter) {
        exportCommon(sysUser, response, queryParameter, false);
    }

    /**
     * 通用导出功能
     * @param sysUser 登录用户
     * @param response 响应
     * @param queryParameter 查询条件
     * @param isSettlement 是否结算
     */
    private void exportCommon(UserLoginCacheDTO sysUser, HttpServletResponse response, PlatformScoreSettlementDetailPageVO queryParameter, boolean isSettlement) {
        // step 1: 组装查询条件
        Specification<PlatformScoreSettlementDetailDO> spec = buildDetailSpecification(sysUser, queryParameter, isSettlement);
        // step 2: 获取结算明细数据
        List<PlatformScoreSettlementDetailDO> resultList = detailRepository.findAll(spec);
        // step 3: 设置导出模板数据
        List<Map<String, Object>> rows = resultList.stream().map(item -> {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put(PlatformScoreSettlementExcelEnum.ORDER_NO.getMessage(), item.getOrderNo());
            map.put(PlatformScoreSettlementExcelEnum.ORDER_ABSTRACT.getMessage(), item.getOrderAbstract());
            map.put(PlatformScoreSettlementExcelEnum.SETTLEMENT_ORDER_TYPE.getMessage(), SettlementOrderTypeEnum.getMessage(item.getSettlementOrderType(), ""));
            map.put(PlatformScoreSettlementExcelEnum.ORDER_TIME.getMessage(), OrderDateTimeUtil.timestampToDateTimeString(item.getOrderTime()));
            map.put(PlatformScoreSettlementExcelEnum.ORDER_TYPE.getMessage(), ReceiptInvoiceOrderTypeEnum.getMessage(item.getOrderType()));
            map.put(PlatformScoreSettlementExcelEnum.ORDER_SCORE.getMessage(), BigDecimal.valueOf(item.getOrderScore()).setScale(2, RoundingMode.HALF_UP));
            map.put(PlatformScoreSettlementExcelEnum.PAY_SCORE.getMessage(), BigDecimal.valueOf(item.getPayScore()).setScale(2, RoundingMode.HALF_UP));
            map.put(PlatformScoreSettlementExcelEnum.PAY_TIME.getMessage(), DateUtil.format(DateUtil.date(item.getPayTime()), "yyyy-MM-dd HH:mm"));
            map.put(PlatformScoreSettlementExcelEnum.RATIO.getMessage(), BigDecimal.valueOf(item.getRatio()).setScale(2, RoundingMode.HALF_UP));
            map.put(PlatformScoreSettlementExcelEnum.SETTLEMENT_AMOUNT.getMessage(), BigDecimal.valueOf(item.getSettlementAmount()).setScale(2, RoundingMode.HALF_UP));
            return map;
        }).collect(Collectors.toList());
        // 获取excel写入器，默认写出到第一个sheet
        ExcelWriter writer = ExcelUtil.getBigWriter();
        // 获取头部样式，获取样式后可自定义样式
        CellStyle style = writer.getHeadCellStyle();
        // 设置文本是否应换行。 将此标志设置为true通过在多行上显示单元格中的所有内容来使所有内容可见
        style.setWrapText(false);
        // 写入数据
        writer.write(rows);
        String fileName = PlatformScoreSettlementExcelEnum.FILE_NAME.getMessage().concat("-") + DateUtil.date() + ".xls";
        // 写入响应
        try (ServletOutputStream out = response.getOutputStream()) {
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            writer.flush(out, true);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            writer.close();
        }
    }

    private Specification<PlatformScoreSettlementDetailDO> buildDetailSpecification(UserLoginCacheDTO sysUser, PlatformScoreSettlementDetailPageVO queryParameter, boolean isSettlement) {
        return (root, query, builder) -> {
            Predicate settlementId = builder.equal(root.get("settlementId").as(Long.class), queryParameter.getSettlementId());
            query.where(settlementId);
            if (!isSettlement) {
                Predicate memberId = builder.equal(root.get("memberId").as(Long.class), sysUser.getMemberId());
                query.where(memberId);
            }
            if (StringUtils.hasLength(queryParameter.getOrderStartTime())) {
                Predicate orderTime = builder.greaterThanOrEqualTo(root.get("orderTime").as(Long.class), DateUtil.parse(queryParameter.getOrderStartTime()).getTime());
                query.where(orderTime);
            }
            if (StringUtils.hasLength(queryParameter.getOrderEndTime())) {
                Predicate orderTime = builder.lessThanOrEqualTo(root.get("orderTime").as(Long.class), DateUtil.parse(queryParameter.getOrderEndTime()).getTime());
                query.where(orderTime);
            }
            if (StringUtils.hasLength(queryParameter.getPayStartTime())) {
                Predicate payTime = builder.greaterThanOrEqualTo(root.get("payTime").as(Long.class), DateUtil.parse(queryParameter.getPayStartTime()).getTime());
                query.where(payTime);
            }
            if (StringUtils.hasLength(queryParameter.getPayEndTime())) {
                Predicate payTime = builder.lessThanOrEqualTo(root.get("payTime").as(Long.class), DateUtil.parse(queryParameter.getPayEndTime()).getTime());
                query.where(payTime);
            }
            if (StringUtils.hasLength(queryParameter.getOrderNo())) {
                Predicate orderNo = builder.like(root.get("orderNo").as(String.class), "%" + queryParameter.getOrderNo().trim() + "%");
                query.where(orderNo);
            }
            if (StringUtils.hasLength(queryParameter.getOrderAbstract())) {
                Predicate orderAbstract = builder.like(root.get("orderAbstract").as(String.class), "%" + queryParameter.getOrderAbstract().trim() + "%");
                query.where(orderAbstract);
            }
            return query.getRestriction();
        };
    }

    /**
     * 分页查询结算明细
     * @author 伍将
     * @date 2020/10/30
     * @param sysUser:
     * @param pageVO:
     * @param isSettlement:
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.common.response.PageData < com.ssy.lingxi.settle.accounts.mode.vo.response.PagePlatformScoreSettlementDetailVO>>
     **/
    public Wrapper<PageData<PagePlatformScoreSettlementDetailVO>> pageSettlementDetail(UserLoginCacheDTO sysUser, PlatformScoreSettlementDetailPageVO pageVO, Boolean isSettlement) {
        // step 1: 组装查询条件
        Specification<PlatformScoreSettlementDetailDO> spec =  (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("settlementId").as(Long.class), pageVO.getSettlementId()));
            if (!isSettlement) {
                list.add(criteriaBuilder.equal(root.get("memberId").as(Long.class), sysUser.getMemberId()));
            }
            if (StringUtils.hasLength(pageVO.getOrderStartTime())) {
                list.add(criteriaBuilder.greaterThanOrEqualTo(root.get("orderTime").as(Long.class), DateUtil.parse(pageVO.getOrderStartTime()).getTime()));
            }
            if (StringUtils.hasLength(pageVO.getOrderEndTime())) {
                list.add(criteriaBuilder.lessThanOrEqualTo(root.get("orderTime").as(Long.class), DateUtil.parse(pageVO.getOrderEndTime()).getTime()));
            }
            if (StringUtils.hasLength(pageVO.getPayStartTime())) {
                list.add(criteriaBuilder.greaterThanOrEqualTo(root.get("payTime").as(Long.class), DateUtil.parse(pageVO.getPayStartTime()).getTime()));
            }
            if (StringUtils.hasLength(pageVO.getPayEndTime())) {
                list.add(criteriaBuilder.lessThanOrEqualTo(root.get("payTime").as(Long.class), DateUtil.parse(pageVO.getPayEndTime()).getTime()));
            }
            if (StringUtils.hasLength(pageVO.getOrderNo())) {
                list.add(criteriaBuilder.like(root.get("orderNo").as(String.class), "%" + pageVO.getOrderNo().trim() + "%"));
            }
            if (StringUtils.hasLength(pageVO.getOrderAbstract())) {
                list.add(criteriaBuilder.like(root.get("orderAbstract").as(String.class), "%" + pageVO.getOrderAbstract().trim() + "%"));
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        // step 2: 组装分页参数
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("orderTime").descending());

        // step 3: 分页查询数据
        Page<PlatformScoreSettlementDetailDO> result = detailRepository.findAll(spec, page);

        // step 4: 组装返回数据
        List<PagePlatformScoreSettlementDetailVO> resultList = result.getContent().stream().map(r -> {
            PagePlatformScoreSettlementDetailVO queryVO = new PagePlatformScoreSettlementDetailVO();
            queryVO.setOrderNo(r.getOrderNo());
            queryVO.setOrderAbstract(r.getOrderAbstract());
            queryVO.setSettlementOrderTypeName(SettlementOrderTypeEnum.getMessage(r.getSettlementOrderType(),""));
            queryVO.setOrderTime(DateUtil.format(DateUtil.date(r.getOrderTime()), "yyyy-MM-dd"));
            queryVO.setOrderTypeName(ReceiptInvoiceOrderTypeEnum.getMessage(r.getOrderType()));
            Double orderScore = Objects.equals(r.getOrderType(), ReceiptInvoiceOrderTypeEnum.CREDITS_EXCHANGE.getCode()) || Objects.equals(r.getOrderType(), ReceiptInvoiceOrderTypeEnum.CHANNEL_POINT_EXCHANGE.getCode())
                    ? null
                    : r.getOrderScore();
            queryVO.setOrderScore(orderScore);
            queryVO.setPayScore(r.getPayScore());
            queryVO.setPayTime(DateUtil.format(DateUtil.date(r.getPayTime()), "yyyy-MM-dd HH:mm"));
            queryVO.setRatio(r.getRatio());
            queryVO.setSettlementAmount(BigDecimal.valueOf(r.getSettlementAmount()).setScale(2, RoundingMode.HALF_UP).doubleValue());

            return queryVO;
        }).collect(Collectors.toList());

        return Wrapper.success(new PageData<>(result.getTotalElements(), resultList));
    }
}
